﻿
namespace SistemaLogistica.DataAccess
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.Common;
    using SistemaLogistica.Business.Entities;

    public class VentaData : BaseDataAccess
    {
        private VentaData() { }

        private readonly static VentaData instancia = new VentaData();

        public static VentaData Instancia
        {
            get { return instancia; }
        }

        public List<Venta> Listar()
        {
            List<Venta> ventas = new List<Venta>();
            DbCommand command = db.GetStoredProcCommand("GetAllFromVenta");

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    Venta venta = new Venta
                    {
                        IdVenta = dr.GetInt32(dr.GetOrdinal("IdVenta")),
                        FechaVenta = dr.GetDateTime(dr.GetOrdinal("FechaVenta")),
                        IdCliente = dr.GetInt32(dr.GetOrdinal("IdCliente")),
                        IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")),
                        Numero = dr.GetString(dr.GetOrdinal("Numero")),
                        Serie = dr.GetString(dr.GetOrdinal("Serie")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Cliente = ClienteData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IdCliente")))
                    };
                   
                    ventas.Add(venta);
                }
            }
            return ventas;
        }

        public List<Venta> Buscar(DateTime fecha)
        {
            List<Venta> ventas = new List<Venta>();
            DbCommand command = db.GetStoredProcCommand("SearchVentas");
            db.AddInParameter(command, "fecha", DbType.DateTime, fecha);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    Venta venta = new Venta
                    {
                        IdVenta = dr.GetInt32(dr.GetOrdinal("IdVenta")),
                        FechaVenta = dr.GetDateTime(dr.GetOrdinal("FechaVenta")),
                        IdCliente = dr.GetInt32(dr.GetOrdinal("IdCliente")),
                        IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")),
                        Numero = dr.GetString(dr.GetOrdinal("Numero")),
                        Serie = dr.GetString(dr.GetOrdinal("Serie")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Cliente = ClienteData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IdCliente")))
                    };

                    ventas.Add(venta);
                }
            }
            return ventas;
        }

        public Venta ObtenerPorID(int idVenta)
        {
            Venta venta = null;
            DbCommand command = db.GetStoredProcCommand("GetVentaByIdVenta");
            db.AddInParameter(command, "idVenta", DbType.Int32, idVenta);

            using (IDataReader dr = db.ExecuteReader(command))
            {
                while (dr.Read())
                {
                    venta = new Venta
                    {
                        IdVenta = dr.GetInt32(dr.GetOrdinal("IdVenta")),
                        FechaVenta = dr.GetDateTime(dr.GetOrdinal("FechaVenta")),
                        IdCliente = dr.GetInt32(dr.GetOrdinal("IdCliente")),
                        IdEmpleado = dr.GetInt16(dr.GetOrdinal("IdEmpleado")),
                        Numero = dr.GetString(dr.GetOrdinal("Numero")),
                        Serie = dr.GetString(dr.GetOrdinal("Serie")),
                        Descripcion = dr.GetString(dr.GetOrdinal("Descripcion")),
                        Cliente = ClienteData.Instancia.ObtenerPorID(dr.GetInt32(dr.GetOrdinal("IdCliente"))),
                        Detalle = DetalleVentaData.Instancia.ListarPorVenta(dr.GetInt32(dr.GetOrdinal("IdVenta")))
                    };
                }
            }
            return venta;
        }

        public void Registrar(Venta venta)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        DbCommand cmdVenta = db.GetStoredProcCommand("InsertVenta");
                        db.AddInParameter(cmdVenta, "descripcion", DbType.String, venta.Descripcion);
                        db.AddInParameter(cmdVenta, "fechaVenta", DbType.DateTime, venta.FechaVenta);
                        db.AddInParameter(cmdVenta, "idCliente", DbType.Int32, venta.IdCliente);
                        db.AddInParameter(cmdVenta, "idEmpleado", DbType.Int32, venta.IdEmpleado);
                        db.AddOutParameter(cmdVenta, "idVenta", DbType.Int32, 11);
                        db.AddInParameter(cmdVenta, "numero", DbType.String, venta.Numero);
                        db.AddInParameter(cmdVenta, "serie", DbType.String, venta.Serie);

                        int result = db.ExecuteNonQuery(cmdVenta, transaction);
                        if (result == 0) throw new Exception("Error al Insertar Venta.");

                        int idVenta = Convert.ToInt32(db.GetParameterValue(cmdVenta, "idVenta"));

                        DbCommand cmdDetalle = db.GetStoredProcCommand("InsertDetalleVenta");
                        db.AddInParameter(cmdDetalle, "cantida", DbType.Decimal);
                        db.AddInParameter(cmdDetalle, "descripcion", DbType.String);
                        db.AddInParameter(cmdDetalle, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetalle, "idVenta", DbType.Int32);
                        db.AddInParameter(cmdDetalle, "monto", DbType.Currency);

                        DbCommand cmdStock = db.GetStoredProcCommand("UpdateStock");
                        db.AddInParameter(cmdStock, "idBien", DbType.Int32);
                        db.AddInParameter(cmdStock, "cantidad", DbType.Decimal);

                        foreach (DetalleVenta d in venta.Detalle)
                        {
                            db.SetParameterValue(cmdDetalle, "cantida", d.Cantida);
                            db.SetParameterValue(cmdDetalle, "descripcion", d.Descripcion);
                            db.SetParameterValue(cmdDetalle, "idBien", d.Bien.IdBien);
                            db.SetParameterValue(cmdDetalle, "idVenta", idVenta);
                            db.SetParameterValue(cmdDetalle, "monto", d.Monto);

                            result = db.ExecuteNonQuery(cmdDetalle, transaction);
                            if (result == 0) throw new Exception("Error al Insertar Detalle de Venta.");

                            db.SetParameterValue(cmdStock, "idBien", d.Bien.IdBien);
                            db.SetParameterValue(cmdStock, "cantidad", -1 * d.Cantida);

                            result = db.ExecuteNonQuery(cmdStock, transaction);
                            if (result == 0) throw new Exception("Error al Actualizar Stock de Bien.");
                        }

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void Modifcar(Venta venta)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        #region Retornar la Venta Ingresada

                        int result = 0;
                        List<DetalleVenta> detalle = DetalleVentaData.Instancia.ListarPorVenta(venta.IdVenta);

                        DbCommand cmdStock = db.GetStoredProcCommand("UpdateStock");
                        db.AddInParameter(cmdStock, "idBien", DbType.Int32);
                        db.AddInParameter(cmdStock, "cantidad", DbType.Decimal);

                        foreach (DetalleVenta d in detalle)
                        {
                            db.SetParameterValue(cmdStock, "idBien", d.Bien.IdBien);
                            db.SetParameterValue(cmdStock, "cantidad", d.Cantida);

                            result = db.ExecuteNonQuery(cmdStock, transaction);
                            if (result == 0) throw new Exception("Error al Retornar el Stock del Bien.");
                        }

                        DbCommand cmdEliminarDetalle = db.GetStoredProcCommand("DeleteDetalleVentaByVenta");
                        db.AddInParameter(cmdEliminarDetalle, "@idVenta", DbType.Int32, venta.IdVenta);

                        result = db.ExecuteNonQuery(cmdEliminarDetalle, transaction);
                        if (result == 0) throw new Exception("Error al Eliminar el Detalle Antiguo de Venta.");

                        #endregion

                        #region Ingresar Venta Modificada

                        DbCommand cmdVenta = db.GetStoredProcCommand("UpdateVenta");
                        db.AddInParameter(cmdVenta, "descripcion", DbType.String, venta.Descripcion);
                        db.AddInParameter(cmdVenta, "fechaVenta", DbType.DateTime, venta.FechaVenta);
                        db.AddInParameter(cmdVenta, "idCliente", DbType.Int32, venta.IdCliente);
                        db.AddInParameter(cmdVenta, "idEmpleado", DbType.Int32, venta.IdEmpleado);
                        db.AddInParameter(cmdVenta, "idVenta", DbType.Int32, venta.IdVenta);
                        db.AddInParameter(cmdVenta, "numero", DbType.String, venta.Numero);
                        db.AddInParameter(cmdVenta, "serie", DbType.String, venta.Serie);

                        result = db.ExecuteNonQuery(cmdVenta, transaction);
                        if (result == 0) throw new Exception("Error al Insertar Venta.");

                        DbCommand cmdDetalle = db.GetStoredProcCommand("InsertDetalleVenta");
                        db.AddInParameter(cmdDetalle, "cantida", DbType.Decimal);
                        db.AddInParameter(cmdDetalle, "descripcion", DbType.String);
                        db.AddInParameter(cmdDetalle, "idBien", DbType.Int32);
                        db.AddInParameter(cmdDetalle, "idVenta", DbType.Int32);
                        db.AddInParameter(cmdDetalle, "monto", DbType.Currency);

                        cmdStock = db.GetStoredProcCommand("UpdateStock");
                        db.AddInParameter(cmdStock, "idBien", DbType.Int32);
                        db.AddInParameter(cmdStock, "cantidad", DbType.Decimal);

                        foreach (DetalleVenta d in venta.Detalle)
                        {
                            db.SetParameterValue(cmdDetalle, "cantida", d.Cantida);
                            db.SetParameterValue(cmdDetalle, "descripcion", d.Descripcion);
                            db.SetParameterValue(cmdDetalle, "idBien", d.Bien.IdBien);
                            db.SetParameterValue(cmdDetalle, "idVenta", venta.IdVenta);
                            db.SetParameterValue(cmdDetalle, "monto", d.Monto);

                            result = db.ExecuteNonQuery(cmdDetalle, transaction);
                            if (result == 0) throw new Exception("Error al Insertar Detalle de Venta.");

                            db.SetParameterValue(cmdStock, "idBien", d.Bien.IdBien);
                            db.SetParameterValue(cmdStock, "cantidad", -1 * d.Cantida);

                            result = db.ExecuteNonQuery(cmdStock, transaction);
                            if (result == 0) throw new Exception("Error al Actualizar Stock de Bien.");
                        }

                        #endregion

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }
        }

        public void Eliminar(int idVenta)
        {
            using (DbConnection conection = db.CreateConnection())
            {
                conection.Open();
                using (DbTransaction transaction = conection.BeginTransaction())
                {
                    try
                    {
                        #region Retornar la Venta Ingresada

                        int result = 0;
                        List<DetalleVenta> detalle = DetalleVentaData.Instancia.ListarPorVenta(idVenta);

                        DbCommand cmdStock = db.GetStoredProcCommand("UpdateStock");
                        db.AddInParameter(cmdStock, "idBien", DbType.Int32);
                        db.AddInParameter(cmdStock, "cantidad", DbType.Decimal);

                        foreach (DetalleVenta d in detalle)
                        {
                            db.SetParameterValue(cmdStock, "idBien", d.Bien.IdBien);
                            db.SetParameterValue(cmdStock, "cantidad", d.Cantida);

                            result = db.ExecuteNonQuery(cmdStock, transaction);
                            if (result == 0) throw new Exception("Error al Retornar el Stock de Bien.");
                        }

                        DbCommand cmdEliminar = db.GetStoredProcCommand("DeleteVenta");
                        db.AddInParameter(cmdEliminar, "idVenta", DbType.Int32, idVenta);

                        result = db.ExecuteNonQuery(cmdEliminar, transaction);
                        if (result == 0) throw new Exception("Error al Eliminar la Venta.");

                        #endregion

                        transaction.Commit();
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                }
            }                     
        }
    }
}
